#pragma once

#include <iostream>
#include <jsoncpp/json/json.h>
#include <signal.h>
#include "compile.hpp"
#include "Runner.hpp"
#include "../comm/log.hpp"
#include "../comm/Util.hpp"

using namespace std;

namespace ns_com_and_run
{
    using namespace ns_compiler;
    using namespace ns_runner;
    using namespace ns_log;
    class ComAndRun
    {
    public:
        ComAndRun() {}
        ~ComAndRun() {}

    public:
        /**
         * <0   程序非运行错误
         * =0   完成
         * >0  进程收到了信号导致异常崩溃
         */
        static void RemoveTempFile(const string &filename)
        {
            if(FileUtil::ExistFile(PathUtil::Src(filename)))    unlink(PathUtil::Src(filename).c_str());
            if(FileUtil::ExistFile(PathUtil::Comeplieer(filename)))    unlink(PathUtil::Comeplieer(filename).c_str());
            if(FileUtil::ExistFile(PathUtil::Exe(filename)))    unlink(PathUtil::Exe(filename).c_str());
            if(FileUtil::ExistFile(PathUtil::Stdin(filename)))    unlink(PathUtil::Stdin(filename).c_str());
            if(FileUtil::ExistFile(PathUtil::Stdout(filename)))    unlink(PathUtil::Stdout(filename).c_str());
            if(FileUtil::ExistFile(PathUtil::Stderr(filename)))    unlink(PathUtil::Stderr(filename).c_str());

        }
        static string CodeToDesc(int code,const string& filename)
        {
            string desc;
           switch(code)
            {
            case 0:
                desc = "程序运行成功";
                break;
            case -1:
                desc = "程序代码为空";
                break;
            case -2:
                desc = "未知错误";
                break;
            case -3:
                FileUtil::ReadFile(PathUtil::Comeplieer(filename),&desc,true);//EORROr
                break;
            case SIGXCPU:
                desc = "用户时间超时";
                break;
            case SIGABRT:
                desc = "超过内存限制";
                break;
            case SIGFPE:
                desc = "浮点数溢出";
                break;
            default:
                desc = "未知 :" + to_string(code);
                break;
            }
            return desc;
        }
        /*****************************************
         * 输入:
         * code:用户传入代码
         * input:用户对自己的提交的代码进行输入
         * cpu_lim:时间要求
         * mem_lim:内存要求
         * 输出:
         * status:状态码
         * reason:请求结果
         * stdout:程序运行结果
         * stderr:程序运行错误结果
         ******************************************/
        static void start(string &in_json, string *out_json)
        {
            Json ::Value in;
            Json ::Reader reader;
            reader.parse(in_json, in);

            string code = in["code"].asString();
            string input = in["input"].asString();
            int cpu_lim = in["cpu_lim"].asInt();
            int mem_lim = in["mem_lim"].asInt();
            int status_code = 0;
            int ret;
            string filename;
            Json ::Value out;

            if (code.size() == 0)
            {
                status_code = -1; // 代码为空
                goto END;
            }
            //标识唯一文件名
            filename = FileUtil::UniqName();

            // 写文件里
            if (!FileUtil::WriteFile(PathUtil::Src(filename), code))
            {
                status_code = -2; // 未知错误
                goto END;
            }
            if (!Compiler::Compile(filename))
            {
                status_code = -3; // 编译错误
                goto END;
            }

            ret = Runner::Run(filename, cpu_lim, mem_lim);
            if (ret < 0)
            {
                status_code = -2;
                goto END;
            }
            else if (ret > 0)
            {
                status_code = ret; // 程序运行崩溃
                goto END;
            }
            else
            {
                status_code = 0;
            }
        //
        END:
            out["status"] = status_code;
            out["reason"] = CodeToDesc(status_code,filename);
            if (status_code == 0)
            {
                // 读文件
                string _stdout, _stderr;
                FileUtil::ReadFile(PathUtil::Stdout(filename),&_stdout,true);
                out["stdout"] = _stdout;
                FileUtil::ReadFile(PathUtil::Stderr(filename),&_stderr,true);
                out["stderr"] = _stderr;
            }
            Json::StyledWriter writer;    
            // writer["emitUTF8"] = true;                                                                                                                                                              
            *out_json = writer.write(out);
            RemoveTempFile(filename);   //清理临时文件
        }
    };
}